package langdetect;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.carrotsearch.labs.langid.*;

import org.apache.tika.language.*;

import com.cybozu.labs.langdetect.*;

/**
 * Language detection libraries that can be used
 */
enum LDModel {
  /**
   * LangId (Java port) by dweiss of Carrotsearch
   * https://github.com/carrotsearch/langid-java
   */
  LANGID,
  /**
   * Apache Tika http://tika.apache.org/
   */
  TIKA,
  /**
   * Google Chromium's CLD2 by Dick Sites https://code.google.com/p/cld2/
   */
  CLD2,
  /**
   * Language Detecton with Infinity Gram (tuned for short message detection)
   * https://github.com/shuyo/ldig
   */
  LD
}

public class LangDetector {

  public LDModel model;
  public String  inputText;
  private double confidenceThreshold;
  private double confidenceLevel = -1;

  /**
   * Generates a new LangDetect object
   * 
   * @param model
   *          Specifies which language detection library to use.
   * @param threshold
   *          The minimum confidence level for a text to be classified as
   *          English.
   */
  public LangDetector(LDModel model, double threshold) {
    this.model = model;
    this.confidenceThreshold = threshold;
  }

  /**
   * Generates a new LangDetect object
   * 
   * @param model
   *          Specifies which language detection library to use.
   * @param threshold
   *          The minimum confidence level for a text to be classified as
   *          English.
   * @param inputText
   *          The input text to run language detection on.
   */
  public LangDetector(LDModel model, double threshold, String inputText) {
    this.model = model;
    this.confidenceThreshold = threshold;
    this.inputText = inputText;
  }

  /**
   * Given a confidence threshold, determines if the input text is English or
   * not.
   * 
   * @return True if the confidence level for English is above the threshold.
   */
  public boolean isEnglish() throws IllegalStateException {
    if ( 0 > confidenceThreshold || confidenceThreshold > 1 )
      throw new IllegalStateException(
          "Invalid threshold setting. Must be in range [0,1]");

    return ( confidenceThreshold < confidenceLevel );
  }

  /**
   * Getter method for confidenceLevel. If confidenceLevel is negative then
   * something went wrong.
   * 
   * @return confidenceLevel
   */
  public double getConfidenceLevel() {
    return confidenceLevel;
  }

  /**
   * Gets the confidence level of the text being English.
   * 
   * @return The confidence the model has that the input text's language is
   *         English
   */
  public void execute() throws UnsupportedOperationException {
    confidenceLevel = -1;

    // Figure out which model we're using and execute it
    switch ( model ) {
      case LANGID:
        // Setting up LangId
        // LangId Models take at least 2 languages, so let's throw in Spanish
        // just for kicks
        // HashSet<String> langs = new HashSet<String>(Arrays.asList("en",
        // "es"));
        Model langModel = Model.defaultModel();
        LangIdV3 lid = new LangIdV3(langModel);
        lid.reset();
        lid.append(inputText);

        // Now let's find english out of the returned DetectedLanguages
        for ( DetectedLanguage dl : lid.rank(true) )
          if ( dl.getLangCode().equals("en") )
            confidenceLevel = dl.getConfidence();
        break;

      case TIKA:
        LanguageIdentifier li = new LanguageIdentifier(inputText);
        confidenceLevel = li.getLanguage().equals("en") ? 1 : 0;
        // TIKA only exposes it's confidence via toString
        // TODO write an override class to do this in a better way...
        // TODO figure out how to go from geometric mean -> confidence level
        // confidenceLevel =
        // Double.parseDouble(li.toString().split("\\(")[1].split("\\)")[0]);
        // System.out.println(LanguageIdentifier.getSupportedLanguages());
        break;

      // TODO figure out how to get this working...
//      case CLD2:
//      break;

      case LD:
        try {
          DetectorFactory.clear();
          DetectorFactory.loadProfile(new File(ClassLoader.getSystemResource("profiles").getPath()));
          Detector detector = DetectorFactory.create();
          detector.append(inputText);
          confidenceLevel = 0;
          for ( Language lang : detector.getProbabilities() )
            if ( lang.lang.equals("en") )
              confidenceLevel = lang.prob;
        } catch ( Exception e ) {
          System.out.println(e);
        }
        break;

      default:
        throw new UnsupportedOperationException(
            "No implementation for this model exists: " + model);
    }
  }
  
  @Override
  public String toString() {
    return "[Model: " + model + ", Is English: " + isEnglish()
        + ", isEnglish confidence: " + confidenceLevel //+ ", text: " + inputText
        + "]";
  }
}
